/*
 * Copyright 2002-2016 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.springframework.security.web.authentication;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.access.ExceptionTranslationFilter;
import org.springframework.util.StringUtils;
import org.springframework.security.web.savedrequest.SavedRequest;
import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;

/**
 * SavedRequestAwareAuthenticationSuccessHandler 在 SimpleUrlAuthenticationSuccessHandler 的基础上增加了请求缓存的功能，
 * 可以记录之前请求的地址，进而在登录成功后重定向到一开始访问的地址。
 *
 * @author Luke Taylor
 * @since 3.0
 */
public class SavedRequestAwareAuthenticationSuccessHandler extends
		SimpleUrlAuthenticationSuccessHandler {
	protected final Log logger = LogFactory.getLog(this.getClass());

	private RequestCache requestCache = new HttpSessionRequestCache();

	@Override
	public void onAuthenticationSuccess(HttpServletRequest request,
			HttpServletResponse response, Authentication authentication)
			throws ServletException, IOException {

		//（1）首先从 requestCache 中获取缓存下来的请求，
		SavedRequest savedRequest = requestCache.getRequest(request, response);

		//如果没有获取到缓存请求，就说明用户在访问登录页面之前并没有访问其他页面，此时直接调用父类的 onAuthenticationSuccess 方法来处理
		if (savedRequest == null) {
			//最终会重定向到 defaultSuccessUrl 指定的地址。
			super.onAuthenticationSuccess(request, response, authentication);

			return;
		}
		/*
		（2）接下来会获取一个 targetUrlParameter，这个是用户显式指定的、希望登录成功后重定向的地址，
		 例如用户发送的登录请求是 http://localhost:8080/doLogin?target=/hello，
		 这就表示当用户登录成功之后，希望自动重定向到/hello 这个接口。
		 getTargetUrlParameter 就是要获取重定向地址参数的 key，也就是上面的 target，
		 拿到 target 之后，就可以获取到重定向地址了。
		 */
		String targetUrlParameter = getTargetUrlParameter();

		/**
		 （3）如果 targetUrlParameter 存在，或者用户设置了 alwaysUseDefaultTargetUrl 为 true，这个时候缓存下来的请求就没有意义了。
		 此时会直接调用父类的 onAuthenticationSuccess 方法完成重定向。
		 targetUrlParameter 存在，则直接重定向到 targetUrlParameter 指定的地址；
		 alwaysUseDefaultTargetUrl 为 true，则直接重定向到 defaultSuccessUrl 指定的地址；
		 如果targetUrlParameter 存在并且 alwaysUseDefaultTargetUrl 为 true，则重定向到 defaultSuccessUrl指定的地址。
		 */
		if (isAlwaysUseDefaultTargetUrl()
				|| (targetUrlParameter != null && StringUtils.hasText(request
						.getParameter(targetUrlParameter)))) {
			requestCache.removeRequest(request, response);
			super.onAuthenticationSuccess(request, response, authentication);

			return;
		}

		clearAuthenticationAttributes(request);

		//（4）如果前面的条件都不满足，那么最终会从缓存请求 savedRequest 中获取重定向地址，然后进行重定向操作。
		// Use the DefaultSavedRequest URL
		String targetUrl = savedRequest.getRedirectUrl();
		logger.debug("Redirecting to DefaultSavedRequest Url: " + targetUrl);
		getRedirectStrategy().sendRedirect(request, response, targetUrl);
	}

	public void setRequestCache(RequestCache requestCache) {
		this.requestCache = requestCache;
	}
}
